package 框架学习.SpringBoot.原理.springboot原理.自动配置.自动配置的原理.springboot如何自动加入;

/**
 * 自动配置原理——springboot如何自动加入
 */
public class index {
    /**
     * 启动类的<a href="">@SpringBootApplication</a>注解中封装了一个<a href="">@SpringBootConfiguration</a><p>
     * 而<a href="">@SpringBootConfiguration</a>中封装了一个<a href="">@Configuration</a>注解<p>
     * 这就说明，启动类也是一个配置类，所以我们之前可以直接在启动类中声明bean对象<p></p>
     * <p>
     * 而<a href="">@SpringBootApplication</a>注解中又封装了一个<a href="">@ComponentScan</a>注解<p>
     * 这就是启动类自带包扫描功能的原因<p></p>
     *
     * <a href="">@SpringBootApplication</a>注解中封装的另一个注解：<a href="">@EnableAutoConfiguration</a><p>
     * 见名知意，这个注解和自动配置有关。这个注解就是自动配置的核心注解<p>
     * 这个注解底层封装了一个<a href="">@Import(AutoConfigurationImportSelector.class)</a>注解<p>
     * 这个注解导入的是一个ImportSelector的实现类<p>
     * <a href="">AutoConfigurationImportSelector</a>实现了<a href="">DeferredImportSelector</a>接口<p>
     * 而<a href="">DeferredImportSelector</a>接口的父接口就是<a href="">ImportSelector</a><p>
     * 这个实现类中重写的<a href="">selectImports()</a>方法的返回值是这样的：<p>
     * <a href="">StringUtils.toStringArray(autoConfigurationEntry.getConfigurations())</a><p>
     * <a href="">AutoConfigurationEntry autoConfigurationEntry</a>又是return这条语句之前由<a href="">getAutoConfigurationEntry()</a>获得的<p></p>
     *
     * <a href="">getAutoConfigurationEntry()</a>方法：<p>
     * 这个方法构造并返回了一个<a href="">AutoConfigurationEntry autoConfigurationEntry</a>对象<p>
     * 构造的时候传递了两个参数：<p>
     * 1、<a href="">List{@code  <String>} configurations</a><p>
     * 2、<a href="">Set{@code  <String>} exclusions</a><p>
     * 而通过刚才的源码，获取到<a href="">AutoConfigurationEntry autoConfigurationEntry</a>是
     * 通过<a href="">autoConfigurationEntry.getConfigurations()</a>方法获得的<p>
     * 所以我们重点关注<a href="">List{@code  <String>} configurations</a>对象<p></p>
     *
     * <a href="">configurations</a>是一个List集合，这个集合又是调用<a href="">getCandidateConfigurations()</a>方法得到的<p>
     * 我们现在就再来进入<a href="">getCandidateConfigurations()</a>方法来看看集合里封装了什么东西<p></p>
     *
     * <a href="">getCandidateConfigurations()</a>方法：<p>
     * 这个方法的返回值是<a href="">List{@code  <String>}  configurations</a><p>
     * 而这个方法中有一个断言，用来判断<a href="">List{@code  <String>}  configurations</a>是否为空<p>
     * 若为空，报错信息为：<p>
     * <a href="">在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中找不到自动配置类。如果您使用的是自定义打包，请确保该文件正确无误。</a><p>
     * 也就是说，springboot启动时会自动加载<a href="">META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports</a>这个文件中的配置信息<p>
     * 而把这个文件中的配置信息加载出来后就会封装到<a href="">List{@code  <String>}  configurations</a>集合中<p></p>
     * <p>
     * 在层层返回后，就会把这个集合中的内容封装到<a href="">selectImports()</a>方法的返回值中<p>
     * 这个时候，<a href="">selectImports()</a>方法的返回值就是要加入到IOC容器中的bean对象所在类和配置类的全类名<p></p>
     * <p>
     * 现在就只需要找到这份文件：<p>
     * 这类文件一般在我们引入进来的起步依赖中都有<p>
     * 起步依赖的jar包又依赖了一个<a href="">autoconfigure</a> jar包<p>
     * 这个jar包中就有这个文件<p></p>
     * <p>
     * 这个文件中配置的，都是 <a href="">类的全类名</a><p>
     * 这个文件中的内容最终会被读取出来，通过@Import注解把对应bean添加到IOC容器中<p></p>
     * <p>
     * 仔细观察会发现，这些类的后缀都是<a href="">AutoConfiguration</a><p>
     * 其实这些类都是<a href="">自动配置类</a><p></p>
     * <p>
     * 以Gson为例：<p>
     * 文件中配置了Gson的自动配置类<a href="">GsonAutoConfiguration</a><p>
     * 这个自动配置类有一个<a href="">@AutoConfiguration</a>注解<p>
     * 这个类是一个配置类<p>
     * 这个类中还有一个返回<a href="">Gson对象</a>的方法<p>
     * 方法上还有一个<a href="">@Bean</a>注解<p>
     * 所以这个类被加入到IOC容器的时候，<a href="">Gson对象</a>也会被加入到IOC容器<p>
     * 这就实现了我们没有手动将其加入IOC却可以自动注入<p></p>
     * <p></p>
     * <p>
     * 最后一个问题：文件中配置的类众多，是所有的类都会注册为IOC容器中的bean吗？<p>
     * 不是。自动配置类中声明bean对象的方法上（也就是有@Bean注解的方法），还有一个<a href="">@ConditionalOnMissingBean</a>注解<p>
     * 其实除了这个注解以外，还有很多Conditional打头的注解，这些注解的作用就是<a href="">按条件装配</a><p>
     * 满足一定的条件时，才会注册到IOC容器成为bean对象<p>
     *
     * @param args
     */
    public static void main(String[] args) {

    }
}
